package com.infore.statisticsAndAlarm.service.impl;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.infore.statisticsAndAlarm.constant.Constants;
import com.infore.statisticsAndAlarm.constant.ResultConstants;
import com.infore.statisticsAndAlarm.entity.FileType;
import com.infore.statisticsAndAlarm.entity.KnowledgeBase;
import com.infore.statisticsAndAlarm.entity.KnowledgeKeyWorld;
import com.infore.statisticsAndAlarm.enums.ResultStatus;
import com.infore.statisticsAndAlarm.repository.IFileTypeRepository;
import com.infore.statisticsAndAlarm.repository.IKeyWorldRepository;
import com.infore.statisticsAndAlarm.repository.IKnowledgeBaseRepository;
import com.infore.statisticsAndAlarm.select.util.PageObject;
import com.infore.statisticsAndAlarm.service.IKnowledegBaseService;
import com.infore.statisticsAndAlarm.util.ArrayUtils;
import com.infore.statisticsAndAlarm.util.DateUtil;
import com.infore.statisticsAndAlarm.util.Page;
import com.infore.statisticsAndAlarm.util.PageUtil;
import com.infore.statisticsAndAlarm.util.ResultEntity;
import com.infore.statisticsAndAlarm.util.Size;

@Service
public class KnowledegBaseServiceImpl implements IKnowledegBaseService {

	@Autowired
	private IKnowledgeBaseRepository iKnowledgeBaseRepository;
	@Autowired
	private IFileTypeRepository iFileTypeRepository;
	@Autowired
	private IKeyWorldRepository iKeyWorldRepository;
	@Value("${fileRoot}")
	private String fileRoot;

	@SuppressWarnings("serial") // 判断查询知识库文件类别
	public List<KnowledgeBase> judgeBases(String knowledgeType, String fileType, String keyWorld) {
		List<KnowledgeBase> bases = new ArrayList<KnowledgeBase>();
		// 默认查询所有
		if (StringUtils.isBlank(knowledgeType) && StringUtils.isBlank(keyWorld) && StringUtils.isBlank(fileType)) {
			bases = iKnowledgeBaseRepository.findAll();
		} else {
			bases = iKnowledgeBaseRepository.findAll(new Specification<KnowledgeBase>() {
				@SuppressWarnings("unchecked")
				public Predicate toPredicate(Root<KnowledgeBase> root, CriteriaQuery<?> query,
						CriteriaBuilder criteriaBuilder) {
					List<Predicate> predicates = new ArrayList<Predicate>();
					// 根据关键词模糊搜索
					if (StringUtils.isNotBlank(keyWorld)) {
						predicates.add(
								criteriaBuilder.or(criteriaBuilder.like(root.get("fileName"), "%" + keyWorld + "%"),
										criteriaBuilder.like(root.get("fileDescribe"), "%" + keyWorld + "%")));
					}
					// 根据知识库大类别查询
					if (StringUtils.isNotBlank(knowledgeType)) {
						predicates.add(criteriaBuilder.equal(root.get("knowledgeType"), knowledgeType));
					}
					// 根据知识库小类别查询
					if (StringUtils.isNotBlank(fileType)) {
						@SuppressWarnings("rawtypes")
						Join join = root.join("fileType");
						predicates.add(criteriaBuilder.equal(join.get("fileTypeId").as(String.class),fileType));
					}
					return query.where(predicates.toArray(new Predicate[predicates.size()]))
							.orderBy(criteriaBuilder.desc(root.get("filePublishTime"))).getRestriction();
				}
			});
			// 修改热词搜索次数
			if (StringUtils.isNotBlank(keyWorld)) {
				try {
					KnowledgeKeyWorld hotWorld = new KnowledgeKeyWorld();
					KnowledgeKeyWorld oldWorld = iKeyWorldRepository.findOneByKeyWorldName(keyWorld);
					if (oldWorld != null) {
						Integer num = Integer.parseInt(oldWorld.getKeyWorldNum());
						num++;
						oldWorld.setKeyWorldNum(num + "");
						hotWorld = oldWorld;
					} else {
						hotWorld.setKeyWorldName(keyWorld);
						hotWorld.setKeyWorldNum("1");
					}
					iKeyWorldRepository.saveAndFlush(hotWorld);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		return bases;
	}

	@SuppressWarnings("unchecked")
	public ResultEntity query(String knowledgeType, String fileType, String keyWorld, PageObject pageObject) {
		List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();// 结果集
		Map<String, Object> typeMap = new HashMap<String, Object>();// 存放每一类具体文件
		List<KnowledgeBase> value = new ArrayList<KnowledgeBase>();
		Map<String, Object> typeFlag = new HashMap<String, Object>();// 标志用来判断是否存在
		List<KnowledgeBase> knowledgeBases = judgeBases(knowledgeType, fileType, keyWorld);// 得到查询结果集
		Size size = new Size();
		// 判断是否分页
		if (pageObject != null && pageObject.getPageNumber() != null && pageObject.getPageSize() != null) {
			Page<KnowledgeBase> page = PageUtil.inventedObjectPage(knowledgeBases, pageObject);
			return new ResultEntity(ResultStatus.SUCCESS, Constants.QUERY_SUCCESS).setPage(page);
		}
		for (KnowledgeBase knowledgeBase : knowledgeBases) {
			// 如果文件类型已经存在
			if (!typeFlag.containsKey(knowledgeBase.getKnowledgeType())) {
				typeMap = new HashMap<String, Object>();
				value = new ArrayList<KnowledgeBase>();
				typeMap.put("type", knowledgeBase.getKnowledgeType());
				typeMap.put("folder", value);
				size = new Size();
				typeMap.put("size", size);
				value.add(knowledgeBase);
				typeFlag.put(knowledgeBase.getKnowledgeType(), value);
				list.add(typeMap);
				// 设置该类型下的文件数目
				int length = value.size();
				size.setSize(length);
			} else {
				value = (List<KnowledgeBase>) typeFlag.get(knowledgeBase.getKnowledgeType());
				value.add(knowledgeBase);
				// 设置该类型下的文件数目
				int length = value.size();
				size.setSize(length);
			}
		}
		Map<String, Object> suMap = new HashMap<String, Object>();
		suMap.put("sum", knowledgeBases.size());
		return new ResultEntity(ResultStatus.SUCCESS, Constants.QUERY_SUCCESS).setDataList(list).setInfo(suMap);
	}

	public ResultEntity add(MultipartFile file, String knowledgeType, String fileType, String fileDescribe,String fileName) {
		KnowledgeBase knBase = new KnowledgeBase();
		FileType fileTypeOld = iFileTypeRepository.findById(fileType).orElse(null);
		// 先判断文件类别是否存在
		if (fileTypeOld == null) {
			return new ResultEntity(ResultStatus.SUCCESS, "文件类型不存在");
		}
		if (file != null) {
			// 文件路径
			String filePath = fileRoot;
			File fileMkdir = new File(filePath);// 判断文件目录是否存在
			if (!fileMkdir.exists()) {
				fileMkdir.mkdir();
			}
			// 取得当前上传文件的文件名称
			String originalFilename = file.getOriginalFilename();
			//修改文件名称
			if (StringUtils.isNotBlank(fileName) && originalFilename.contains(".")) {
				String fileIndex = originalFilename.substring(originalFilename.lastIndexOf("."));
				originalFilename = fileName + fileIndex;
			}
			File folder = new File(filePath, originalFilename);
			try {
				file.transferTo(folder);
				// 封装知识库文件
				knBase.setKnowledgeType(knowledgeType);
				knBase.setFileName(originalFilename);
				knBase.setFileDescribe(fileDescribe);
				knBase.setFilePublishTime(DateUtil.getSystemTime());
				knBase.setFileType(fileTypeOld);
				knBase.setFileNum("0");
				iKnowledgeBaseRepository.saveAndFlush(knBase);
			} catch (IOException e) {
				return new ResultEntity(ResultStatus.SUCCESS, ResultConstants.FILE_NAME_ERROR);
			}
		}
		return new ResultEntity(ResultStatus.SUCCESS, Constants.FILE_SUCCESS);
	}

	public ResultEntity delete(String ids) {
		List<String> idsList = ArrayUtils.stringToList(ids);
		List<KnowledgeBase> knowledgeBases = iKnowledgeBaseRepository.findByKnowledgeBaseIdIn(idsList);
		for (KnowledgeBase knowledgeBase : knowledgeBases) {
			String fileName = knowledgeBase.getFileName();
			String sb = fileRoot + fileName;
			File file = new File(sb);
			if (file.exists()) {
				// 删除文件
				file.delete();
			}
		}
		iKnowledgeBaseRepository.deleteByKnowledgeBaseIdIn(idsList);
		return new ResultEntity(ResultStatus.SUCCESS, Constants.DELETE_SUCCESS);
	}

	public ResultEntity download(HttpServletResponse response, String id) {
		KnowledgeBase knowledgeBase = iKnowledgeBaseRepository.findOneByKnowledgeBaseId(id);
		// 先更新文件浏览次数
		Integer num = Integer.parseInt(knowledgeBase.getFileNum());
		num++;
		knowledgeBase.setFileNum(num + "");
		try {
			iKnowledgeBaseRepository.saveAndFlush(knowledgeBase);
		} catch (Exception e1) {
			e1.printStackTrace();
		}
		// 要上传的文件名字
		String fileName = knowledgeBase.getFileName();
		// 通过文件的保存文件夹路径加上文件的名字来获得文件
		File file = new File(fileRoot, fileName);
		// 当文件存在
		if (file.exists()) {
			response.reset(); // 非常重要
			response.setCharacterEncoding("utf-8");
			// 首先设置响应的内容格式是force-download，那么你一旦点击下载按钮就会自动下载文件了
			response.setContentType("application/force-download");
			// 通过设置头信息给文件命名，也即是，在前端，文件流被接受完还原成原文件的时候会以你传递的文件名来命名
			try {
				fileName = URLEncoder.encode(fileName, "UTF-8");
				response.setHeader("Content-Disposition",
						"attachment; filename=" + new String(fileName.getBytes(), "ISO8859-1"));
			} catch (UnsupportedEncodingException e1) {
				e1.printStackTrace();
			}
			// 进行读写操作
			byte[] buffer = new byte[1024];
			FileInputStream fis = null;
			BufferedInputStream bis = null;
			try {
				fis = new FileInputStream(file);
				bis = new BufferedInputStream(fis);
				OutputStream os = response.getOutputStream();
				// 从源文件中读
				int i = bis.read(buffer);
				while (i != -1) {
					// 写到response的输出流中
					os.write(buffer, 0, i);
					i = bis.read(buffer);
				}
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				try {
					if (bis != null) {
						bis.close();
					}
					if (fis != null) {
						fis.close();
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

		}
		return null;
	}

}
